#ifndef __Service__
#define __Service__
#include "config.hpp"
#include "log.hpp"
#include "httplib.h"
#include "Data_Man.hpp"
#include <ctime>
extern cloud::DataManager *data;
namespace cloud
{
    class Service
    {
    private:
        // static std::string UnicodeToUTF8(const std::string& input) 
        // {
        //     std::string output;
        //     std::istringstream stream(input);

        //     while (!stream.eof()) {
        //         std::string hex;
        //         stream >> hex;

        //         if (!hex.empty() && hex.substr(0, 2) == "\\u") {
        //             unsigned int value;
        //             std::stringstream ss;
        //             ss << std::hex << hex.substr(2);
        //             ss >> value;

        //             if (value <= 0x7F) {
        //                 output += static_cast<char>(value);
        //             } else if (value <= 0x7FF) {
        //                 output += static_cast<char>(0xC0 | ((value >> 6) & 0x1F));
        //                 output += static_cast<char>(0x80 | (value & 0x3F));
        //             } else if (value <= 0xFFFF) {
        //                 output += static_cast<char>(0xE0 | ((value >> 12) & 0x0F));
        //                 output += static_cast<char>(0x80 | ((value >> 6) & 0x3F));
        //                 output += static_cast<char>(0x80 | (value & 0x3F));
        //             } else if (value <= 0x10FFFF) {
        //                 output += static_cast<char>(0xF0 | ((value >> 18) & 0x07));
        //                 output += static_cast<char>(0x80 | ((value >> 12) & 0x3F));
        //                 output += static_cast<char>(0x80 | ((value >> 6) & 0x3F));
        //                 output += static_cast<char>(0x80 | (value & 0x3F));
        //             }
        //         } else {
        //             output += hex;
        //         }
        //     }

        //     return output;
        // }
        static std::string DecodeUnicode(const std::string& input) {
            std::string output;
            std::istringstream stream(input);

            while (!stream.eof()) {
                std::string token;
                stream >> token;

                if (!token.empty() && token.substr(0, 2) == "\\u") {
                    int value = std::stoi(token.substr(2), nullptr, 16);
                    output += static_cast<char>(value);
                } else {
                    output += token;
                }
            }

            return output;
        }

        static std::string TimetoStr(time_t t)
        {
            std::string tmp = std::ctime(&t);
            return tmp;
        }
        static void UpLoad(const httplib::Request &req, httplib::Response &rsp) // 上传请求处理
        {
            auto ret = req.has_file("file"); // 看看请求里有没有这个字段，如果有的话就说明请求内容中有一个文件等待上传
            if (ret == false)
            {
                rsp.status = 404;
                return;
            }
            /*如果备份文件夹不存在，就创建一个备份文件夹*/
            std::string backdir = cloud::Config::Getinstance()->Get_back_dir();

            //std::cout<<backdir<<std::endl;

            backdir.pop_back();
            cloud::FileUtil fu(backdir);
            if (fu.Exists() == false)
                fu.CreateDirectory();
            // 走到这里说明有一个文件等待上传
            // 读取这个文件的内容，将他存放在备份文件目录下，更新备份管理模块
            const auto &file = req.get_file_value("file"); // 拿到文件内容
            // 将文件存放在备份文件目录下
            std::string body = file.content;
            std::string filename = DecodeUnicode(cloud::FileUtil(file.filename).FileName());
            
            // cloud::FileUtil fu(ttttttt.dat);
            // fu.SetContent(cloud::FileUtil(file.filename).FileName());
            // std::cout<<cloud::FileUtil(file.filename).FileName()<<std::endl;
            // std::cout<<filename<<std::endl;



            cloud::FileUtil storage(cloud::Config::Getinstance()->Get_back_dir() + filename);
            storage.SetContent(&body); // 将文件写入备份文件目录下
            cloud::Backupinfo bi;
            bi.NewBackupinfo(cloud::Config::Getinstance()->Get_back_dir() + filename);
            data->insert(bi); // 更新备份文件管理模块信息
        }
        static void ListShow(const httplib::Request &req, httplib::Response &rsp) // 展示页面处理
        {
            // 当用户请求http页面时，就组织好一个http页面
            std::stringstream ss;
            ss << "<html><head><title>Download</title><meta charset=\"UTF-8\"></head><body><h1>Download</h1><table>";
            // 以上都是固定的，这一部分是要遍历数据管理模块，拿到所有备份文件信息
            std::vector<cloud::Backupinfo> arr;
            data->GetAll(&arr); // 拿到所有备份文件信息
            for (auto b : arr)
            {

                ss << "<tr>";
                ss << "<td><a href='";
                ss << cloud::Config::Getinstance()->Get_download_prefix().c_str() << cloud::FileUtil(b._real_path).FileName().c_str();
                ss << "'>" << cloud::FileUtil(b._real_path).FileName().c_str() << "</a></td>";
                ss << "<td align='right'>" << TimetoStr(b._mtime) << "</td>";
                ss << "<td align='right'>" << std::to_string(std::min(b._fsize / 1024,(size_t)1)) << "k</td>";
                ss << "</tr>";
            }
            ss << "</table></body></html>";
            rsp.body = ss.str();
            rsp.set_header("Content-Type", "text/html");
            rsp.status = 200;
            return;
        }
        static std::string GetETag(cloud::Backupinfo &bi)
        {
            std::string ret;
            cloud::FileUtil fu(bi._real_path);
            ret += fu.FileName();
            ret += "-";
            ret += std::to_string(bi._fsize);
            ret += "-";
            ret += std::to_string(bi._mtime);
            return ret;
        }
        static void DownLoad(const httplib::Request &req, httplib::Response &rsp) // 下载请求处理
        {
            // 收到一个下载请求后
            std::string srcpath = req.path;
            cloud::Backupinfo bi; // 判断这个文件是否已经被压缩了
            data->GetOneByurl(srcpath, &bi);
            if (bi._pack_flag == 1)
            {
                std::string real_packup_path = bi._pack_path; // 拿到真实存放路径
                cloud::FileUtil fu(real_packup_path);
                fu.UnCompress(bi._real_path); // 解压缩后的文件放到backdir中
                fu.Remove();
                bi._pack_flag = 0;
                data->Update(bi);
            }
            // 接下来就是把文件发送回去
            /*断点续传功能*/
            bool resume = false;
            if (req.has_header("If-Range") == true) // 如果有if-range这个字段就是断点续传请求，但是只有在后续的etag字段判定成功后才能进行断点续传
            {
                std::string oldETag = GetETag(bi);
                if (oldETag == req.get_header_value("If-Range"))
                {
                    resume = true;
                }
            }
            //std::cout<<resume<<std::endl;
            cloud::FileUtil info(bi._real_path);
            std::string body;
            if (info.GetContent(&body) == false)
            {
                rsp.body = "请刷新重试";
                return;
            }
            if (resume == false)
            {
                //std::cout<<"我要从头开始传输"<<std::endl;
                rsp.body = body;
                rsp.set_header("ETag", GetETag(bi));
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("Content-Type", "application/octet-stream");
                rsp.status = 200;
            }
            else
            //搞了半天人家httplib库里面自己支持了断点续传功能
            //如果人家没支持断点续传功能呢？
            //std::string range = req.get_header_value("Range");-----bytes=start-end 然后我们需要自己解析这个字段，拿到区间
            //然后从body里面substr······
            //然后rsp.set_header("Content-Range","bytes=start-end/fsize");
            {
                //std::cout<<"我要准备断点续传了哦"<<std::endl;
                rsp.body = body;
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("ETag",GetETag(bi));
                rsp.set_header("Content-Type", "application/octet-stream");
                rsp.status = 206;
                
            }
        }

    public:
        Service()
        {
            cloud::Config *conf = cloud::Config::Getinstance();
            _server_ip = conf->Get_server_ip();
            _server_port = conf->Get_server_port();
            _download_prefix = conf->Get_download_prefix();
        }
        bool run()
        {
            _server.Post("/upload", UpLoad);
            _server.Get("/listshow", ListShow);
            _server.Get("/", ListShow);
            std::string download_url = _download_prefix + "(.*)";
            _server.Get(download_url, DownLoad);
            _server.listen(_server_ip, _server_port);
            std::cout << _server_ip << std::endl;
            std::cout << _server_port << std::endl;
            return true;
        }

    private:
        std::string _server_ip;       // 服务器ip地址
        int _server_port;             // 服务器端口
        std::string _download_prefix; // 服务器下载请求前缀
        httplib::Server _server;      // 服务器对象
    };
}

#endif